home *** CD-ROM | disk | FTP | other *** search
- /*
- * DOMAIN.C -- domain name system stub resolver
- *
- * Original code by Phil Karn, KA9Q
- *
- * 04-90 -- Bill Simpson added address->name resolution, time-to-live,
- * thru memory caching, generalized multi-record multi-type searches,
- * 10-90 and many minor changes to conform more closely to the RFCs.
- *
- * 06-89 -- Gerard van der Grinten, PA0GRI
- * thru Lots of changes and inprovements including server code.
- * 02-91
- *
- * Jan 92 Bill Simpson added CNAME support to domainsuffix routine.
- *
- * Jun 92 Johan. K. Reinalda, WG7J
- * Ported the Domain Name Server from PA0GRI's 910828 .
- * Version info see down below
- *
- */
-
- #include "global.h"
- #include "ctype.h"
- #include "commands.h"
- #ifndef MSDOS
- #include <time.h>
- #endif
- #include <sys/stat.h>
- #include "mbuf.h"
- #include "netuser.h"
- #include "ip.h"
- #include "domain.h"
- #include "files.h"
- #include "session.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: domain.c,v 1.34 1997/08/19 01:19:22 root Exp root $";
- #endif
-
- #ifdef UNIX
- /*lint -esym(534, tfprintf) -esym(652, fprintf, printf) */
- #undef fprintf
- #define fprintf tfprintf
- #undef printf
- #define printf tprintf
- #endif
-
- #undef DEBUG /* for certain trace messages */
- #undef DEBUG_PAIN /* for painful debugging */
-
- extern int main_exit; /* from main program (flag) */
- extern int Mprunning; /* from main program (flag) */
- extern int Mprunning_err; /* from main program (flag) */
- int DTranslate; /* do IP address to domain name translation */
- int DVerbose; /* Use all of resolved name or first element */
- static int DTransing; /* flag that says we are translating */
- static int DLTranslate; /* translate using LOCAL domain.txt ONLY */
-
-
- static struct rr *Dcache; /* Cache of resource records */
- static int Dcache_size = 20; /* size limit */
- static time_t Dcache_time = 0L; /* timestamp */
-
- static int Dfile_clean; /* discard expired records (flag) */
- static int Dfile_reading; /* read interlock (count) */
- static int Dfile_writing; /* write interlock (count) */
-
- struct proc *Dfile_updater;
- static int32 Dfile_wait_absolute; /* timeout Clock time */
- static int Dfile_wait_relative = 300; /* timeout file activity (seconds) */
-
- static struct dserver *Dservers;/* List of potential servers */
- static int Dserver_retries = 3; /* Attempts to reach servers */
- static int32 Dserver_maxwait = 60L; /* maximum server timeout limit (seconds) */
-
- /* KG7CP - */
- static int Dfile_upd = 0; /* update the domain file (flag) */
-
- #ifdef DSERVER
- static int32 Dns_ttl = 0L; /* time-to-live of dns answers */
- static int dns_maxcli = 6; /* max number of simultaneous DNS processes */
- static int dns_process_count = 0;
- #endif
-
- /* N7IPB */
- static int Dsubnet_translate; /* Translate subnet and broadcast addresses */
-
- static char *Dsuffix; /* Default suffix for names without periods */
- static int Dsuffixl; /* size of Dsuffix (less computing to do */
- static int Dtrace;
- static const char *Dtypes[] =
- {
- "",
- "A",
- "NS",
- "MD",
- "MF",
- "CNAME",
- "SOA",
- "MB",
- "MG",
- "MR",
- "NULL",
- "WKS",
- "PTR",
- "HINFO",
- "MINFO",
- "MX",
- "TXT"
- };
-
- #define NDTYPES 17
-
- #ifdef DSERVER
- /* Following array used by domain query for type field */
-
- static const char *Dtypes1[] =
- {
-
- "A", "1", /* Host address */
- "NS", "2", /* Name server */
- "MD", "3", /* Mail destination (obsolete) */
- "MF", "4", /* Mail forwarder (obsolete) */
- "CNAME", "5", /* Canonical name */
- "SOA", "6", /* Start of Authority */
- "MB", "7", /* Mailbox name (experimental) */
- "MG", "8", /* Mail group member (experimental) */
- "MR", "9", /* Mail rename name (experimental) */
- "NULL", "10", /* Null (experimental) */
- "WKS", "11", /* Well-known sockets */
- "PTR", "12", /* Pointer record */
- "HINFO", "13", /* Host information */
- "MINFO", "14", /* Mailbox information (experimental)*/
- "MX", "15", /* Mail exchanger */
- "TXT", "16", /* Text strings */
- "AXFR", "252", /* Transfer zone of authority */
- "MAILB", "253", /* Transfer mailbox records */
- "MAILA", "254", /* Transfer mail agent records */
- "ANY", "255" /* Matches any type */
- };
- #endif
-
- #define NDTYPES1 40
-
- #ifndef TNOS_68K
- static const char delim[] = " \t\r\n";
- #else
- static const char delim[] = " \t\r\l";
- #endif
-
- #ifdef DSERVER
- static int dodomresolve (int argc, char *argv[], void *p);
- static int dodnsquery (int argc, char *argv[], void *p);
- #endif /* DSERVER */
-
- static struct rr *resolve_rr (const char *dname,int16 dtype,int recurse);
- static int docache (int argc, char *argv[], void *p);
- static int dosuffix (int argc, char *argv[], void *p);
- static int dotranslate (int argc, char *argv[], void *p);
- static int doverbose (int argc, char *argv[], void *p);
- static int docacheclean (int argc, char *argv[], void *p);
- static int docachelist (int argc, char *argv[], void *p);
- static int docachesize (int argc, char *argv[], void *p);
- static int docachewait (int argc, char *argv[], void *p);
- static int dofileupdate (int argc, char *argv[], void *p);
- static int docachedump (int argc, char *argv[], void *p);
- static int dosubnettrans (int argc, char *argv[], void *p);
- static void dlist_add (struct dserver * dp);
- static void dlist_drop (struct dserver * dp);
- static int dodnsadd (int argc, char *argv[], void *p);
- static int dodnsdrop (int argc, char *argv[], void *p);
- static int dodnslist (int argc, char *argv[], void *p);
- static int dodnsmaxw (int argc, char *argv[], void *p);
- static int dodnsretry (int argc, char *argv[], void *p);
- static int dodnstrace (int argc, char *argv[], void *p);
- static int dodomlook (int argc, char *argv[], void *p);
- static int dolocaltrans (int argc, char *argv[], void *p);
- static int check_ttl (struct rr * rrlp);
- static int compare_rr (struct rr * search_rrp, struct rr * target_rrp);
- static int compare_rr_list (struct rr * rrlp, struct rr * target_rrp);
- static struct rr *copy_rr (struct rr * rrp);
- static struct rr *copy_rr_list (struct rr * rrlp);
- static struct rr *make_rr (int source,
- char *dname, int16 class, int16 type, int32 ttl, int16 rdl, void *data);
- static void dcache_add (struct rr * rrlp);
- static void dcache_drop (struct rr * rrp);
- static struct rr *dcache_search (struct rr * rrlp);
- static void dcache_update (struct rr * rrlp);
- static struct rr *get_rr (FILE * fp, struct rr * lastrrp);
- static void put_rr (FILE * fp, struct rr * rrp);
- static struct rr *dfile_search (struct rr * rrlp);
- static struct rr *dfile_search_file (struct rr * rrlp, const char *filename);
- static void dfile_update (int s, void *unused, void *p);
- static void dumpdomain (struct dhdr * dhp, int32 rtt);
- static int dns_makequery (int16 op, struct rr * rrp, char *buffer, int16 buflen);
- static void dns_query (struct rr * rrlp);
- static int isaddr (const char *s);
- static struct rr *resolver (struct rr * rrlp);
-
- #ifdef DSERVER
- static void free_dhdr (struct dhdr *);
- static int dodns_ttl (int argc, char *argv[], void *p);
- static int dodnsserver (int argc, char *argv[], void *p);
- static int dodnsmaxcli (int argc, char *argv[], void *p);
- static void proc_query (int, void *, void *);
- static void drx (int, void *, void *);
- #endif
-
- /**
- ** Domain Resolver Commands
- **/
-
- static struct cmds Dcmds[] =
- {
- { "addserver", dodnsadd, 0, 2, "domain addserver <hostid>" },
- { "cache", docache, 0, 0, NULLCHAR },
- #ifdef DSERVER
- { "dns", dodnsserver, 0, 0, NULLCHAR },
- #endif
- { "dropserver", dodnsdrop, 0, 2, "domain dropserver <hostid>" },
- { "list", dodnslist, 0, 0, NULLCHAR },
- { "localtrans", dolocaltrans, 0, 0, NULLCHAR },
- #ifdef ALLCMD
- { "look", dodomlook, 512, 2, "domain look \"<search text>\"" },
- #endif
- #ifdef DSERVER
- { "maxclients", dodnsmaxcli, 0, 0, NULLCHAR },
- #endif
- { "maxwait", dodnsmaxw, 0, 0, NULLCHAR },
- #ifdef DSERVER
- { "query", dodnsquery, 512, 3, "domain query <dns hostid> <hostid> [type] [maxtries] [timeout-ms]" },
- { "resolve", dodomresolve, 512, 2, "domain resolve <hostid>" },
- #endif /* DSERVER */
- { "retries", dodnsretry, 0, 0, NULLCHAR },
- { "subnet", dosubnettrans, 0, 0, NULLCHAR },
- { "suffix", dosuffix, 0, 0, NULLCHAR },
- { "trace", dodnstrace, 0, 0, NULLCHAR },
- { "translate", dotranslate, 0, 0, NULLCHAR },
- #ifdef DSERVER
- { "ttl", dodns_ttl, 0, 0, NULLCHAR },
- #endif
- { "update", dofileupdate, 0, 0, NULLCHAR },
- { "verbose", doverbose, 0, 0, NULLCHAR },
- { NULLCHAR, NULL, 0, 0, NULLCHAR }
- };
-
-
- static struct cmds Dcachecmds[] =
- {
- { "clean", docacheclean, 0, 0, NULLCHAR },
- { "dump", docachedump, 0, 0, NULLCHAR },
- { "flush", docachedump, 0, 0, NULLCHAR },
- { "list", docachelist, 512, 0, NULLCHAR },
- { "size", docachesize, 0, 0, NULLCHAR },
- { "wait", docachewait, 0, 0, NULLCHAR },
- { NULLCHAR, NULL, 0, 0, NULLCHAR }
- };
-
-
-
- int
- dodomain (int argc, char *argv[], void *p)
- {
- return subcmd (Dcmds, argc, argv, p);
- }
-
-
-
- int
- docache (int argc, char *argv[], void *p)
- {
- return subcmd (Dcachecmds, argc, argv, p);
- }
-
-
-
- static int
- dosuffix (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc < 2) {
- if (Dsuffix != NULLCHAR)
- tprintf ("%s\n", Dsuffix);
- else
- tputs ("No domain suffix defined.\n");
- return 0;
- }
- if (strcmp (argv[1], "none") == 0) {
- if (Dsuffix != NULLCHAR) {
- free (Dsuffix);
- Dsuffix = NULLCHAR; /* clear out suffix */
- Dsuffixl = 0;
- }
- } else if (argv[1][strlen (argv[1]) - 1] != '.') {
- tprintf (" %s is not a valid suffix.\n", argv[1]);
- return 1;
- } else {
- if (Dsuffix != NULLCHAR)
- free (Dsuffix);
- Dsuffix = strdup (argv[1]);
- Dsuffixl = (int) strlen (Dsuffix);
- }
- return 0;
- }
-
-
-
- static int
- dolocaltrans (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&DLTranslate, "Translate IP address only using LOCAL domain.txt", argc, argv);
- }
-
-
-
- static int
- dotranslate (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&DTranslate, "Translate IP address to host names", argc, argv);
- }
-
-
-
- static int
- doverbose (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&DVerbose, "Verbose translation of host names", argc, argv);
- }
-
-
-
- static int
- dodnsmaxw (int argc, char *argv[], void *p OPTIONAL)
- {
- return setlong (&Dserver_maxwait, "Server response timeout limit (sec)", argc, argv);
- }
-
-
-
- static int
- docacheclean (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&Dfile_clean, "Discard expired records", argc, argv);
- }
-
-
-
- #ifdef DSERVER
- /*KG7CP - set the standard time-to-live for nameserver answers */
- static int
- dodns_ttl (int argc, char *argv[], void *p OPTIONAL)
- {
- return setlong (&Dns_ttl, "Time-to-live of nameserver answers (secs)", argc, argv);
- }
- #endif
-
-
-
- /* KG7CP - remove all entries from the cache */
- static int
- docachedump (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
- {
- struct rr *dump_rrlp;
-
- dump_rrlp = Dcache;
- Dcache = NULLRR;
- free_rr (dump_rrlp);
- return 0;
- }
-
-
-
- /* KG7CP - flag whether the domain file is updated from name server
- * quey responses
- */
- static int
- dofileupdate (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&Dfile_upd, "Update Domain file", argc, argv);
- }
-
-
-
- /* N7IPB - Enable or Disable translation of subnet and broadcast addresses */
- static int
- dosubnettrans (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&Dsubnet_translate, "Translate IP subnet and broadcast addresses", argc, argv);
- }
-
-
-
- static int
- docachelist (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- struct rr *rrp;
- char tmpname[80];
- FILE *fp;
- char **margv;
- int count = 0;
-
- margv = (char **) callocw (2, sizeof (char *));
-
- (void) tmpnam (tmpname);
- fp = fopen (tmpname, WRITE_TEXT);
- if (fp) {
- (void) dcache_search (NULLRR); /* update ttl */
- #ifndef UNIX
- rflush ();
- #endif
- for (rrp = Dcache; rrp != NULLRR; rrp = rrp->next) {
- ++count;
- put_rr (fp, rrp);
- }
- (void) fclose (fp);
- }
- if (count) {
- margv[1] = strdup (tmpname);
- (void) morecmd (2, margv, p);
- free (margv[1]);
- free (margv);
- } else
- tputs ("Cache Empty\n");
-
- unlink (tmpname);
- return 0;
- }
-
-
-
- static int
- docachesize (int argc, char *argv[], void *p OPTIONAL)
- {
- int newsize;
- int oldsize;
- int result;
-
- newsize = oldsize = Dcache_size;
- result = setint (&newsize, "Domain memory cache size", argc, argv);
-
- if (newsize > 0) {
- Dcache_size = newsize;
- if (newsize < oldsize)
- (void) dcache_search (NULLRR); /* update size */
- }
- return result;
- }
-
-
-
- static int
- docachewait (int argc, char *argv[], void *p OPTIONAL)
- {
- return setint (&Dfile_wait_relative, "Time before Domain file update (secs)", argc, argv);
- }
-
-
-
- static void
- dlist_add (register struct dserver *dp)
- {
- dp->prev = NULLDOM;
- dp->next = Dservers;
- if (Dservers != NULLDOM)
- Dservers->prev = dp;
- Dservers = dp;
- }
-
-
-
- static void
- dlist_drop (register struct dserver *dp)
- {
- if (dp->prev != NULLDOM)
- dp->prev->next = dp->next;
- else
- Dservers = dp->next;
- if (dp->next != NULLDOM)
- dp->next->prev = dp->prev;
- }
-
-
-
- static int
- dodnsadd (int argc, char *argv[], void *p OPTIONAL)
- {
- uint32 address;
- int timeout = 0;
-
- if ((address = resolve (argv[1])) == 0L) {
- tprintf ("Domain Nameserver %s unknown\n", argv[1]);
- return 1;
- }
- if (argc > 2 && argv[2])
- timeout = atoi (argv[2]);
- return add_nameserver (address, timeout);
- }
-
-
- int
- add_nameserver (uint32 address, int timeout)
- {
- struct dserver *dp;
-
- dp = (struct dserver *) callocw (1, sizeof (struct dserver));
-
- dp->address = address;
- if (timeout)
- dp->srtt = timeout * 1000L;
- else
- dp->srtt = 3 * Tcp_irtt; /* Round trip plus processing time */
- dp->mdev = 0;
- dp->timeout = dp->srtt; /* 4 * dp->mdev + dp->srtt;*/
- dlist_add (dp);
- return 0;
- }
-
-
-
- static int
- dodnsdrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
- {
- struct dserver *dp;
- uint32 addr;
-
- addr = resolve (argv[1]);
- for (dp = Dservers; dp != NULLDOM; dp = dp->next)
- if (addr == dp->address)
- break;
-
- if (dp == NULLDOM) {
- tputs ("DNS not found\n");
- return 1;
- }
- dlist_drop (dp);
- free ((char *) dp);
- return 0;
- }
-
-
-
- static int
- dodnslist (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
- {
- register struct dserver *dp;
-
- tputs ("Server address SRTT Mdev Timeout Queries Responses Timeouts\n");
- for (dp = Dservers; dp != NULLDOM; dp = dp->next)
- tprintf ("%-20s%8lu%8lu%10lu%10lu%10lu%10lu\n",
- inet_ntoa (dp->address), dp->srtt, dp->mdev,
- dp->timeout, dp->queries, dp->responses, dp->timeouts);
- return 0;
- }
-
-
-
- static int
- dodnsretry (int argc, char *argv[], void *p OPTIONAL)
- {
- return setint (&Dserver_retries, "DNS retry limit", argc, argv);
- }
-
-
-
- static int
- dodnstrace (int argc, char *argv[], void *p OPTIONAL)
- {
- return setbool (&Dtrace, "DNS tracing", argc, argv);
- }
-
-
-
- /**
- ** Domain Resource Record Utilities
- **/
-
- /* check list of resource records for any expired ones.
- * returns number of expired records.
- */
- static int
- check_ttl (register struct rr *rrlp)
- {
- int count = 0;
-
- while (rrlp != NULLRR) {
- if (rrlp->ttl == 0L)
- count++;
- rrlp = rrlp->next;
- }
- return count;
- }
-
-
-
- /* Compare two resource records.
- * returns 0 if match, nonzero otherwise.
- */
- static int
- compare_rr (register struct rr *search_rrp, register struct rr *target_rrp)
- {
- int i, j, k;
-
- if (search_rrp == NULLRR || target_rrp == NULLRR)
- return -32765;
-
- if (search_rrp->class != target_rrp->class)
- return -32763;
-
- if (search_rrp->type != target_rrp->type && (search_rrp->source != RR_QUERY
- || (target_rrp->type != TYPE_CNAME && target_rrp->type != TYPE_PTR)))
- return -32761;
-
- if (search_rrp->source != RR_INQUERY) {
- /* added to prevent dereferencing null names - shouldn't happen */
- if (!search_rrp->name || !target_rrp->name)
- return -32764;
- i = (int) strlen (search_rrp->name);
- j = (int) strlen (target_rrp->name);
- if (i == j) {
- if ((k = strnicmp (search_rrp->name, target_rrp->name, (unsigned) i)) != 0)
- return k;
- } else {
- if (Dsuffix != NULLCHAR) {
- if (i != j + Dsuffixl + 1)
- return -32759;
- else {
- if (search_rrp->name[j] != '.')
- return -32755;
- if (strnicmp (target_rrp->name
- ,search_rrp->name, (unsigned) j) != 0)
- return -32757;
- }
- } else
- return -32759;
-
- /* match negative records so that they are replaced */
- if (target_rrp->rdlength == 0)
- return 0;
- }
- }
- /* if a query has gotten this far, match it */
- if (search_rrp->source == RR_QUERY)
- return 0;
-
- /* ensure negative records don't replace older records */
- if (search_rrp->rdlength == 0)
- return -32757;
-
- /* match expired records so that they are replaced */
- if (search_rrp->source != RR_INQUERY) {
- if (target_rrp->ttl == 0L)
- return 0;
- }
- /* Note: rdlengths are not compared because they vary depending
- * on the representation (ASCII or encoded) this record was
- * generated from.
- */
-
- switch (search_rrp->type) {
- case TYPE_A:
- i = search_rrp->rdata.addr != target_rrp->rdata.addr;
- break;
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- if (!search_rrp->rdata.data || !target_rrp->rdata.data)
- i = -32764;
- else
- i = stricmp (search_rrp->rdata.data, target_rrp->rdata.data);
- break;
- case TYPE_HINFO:
- i = stricmp (search_rrp->rdata.hinfo.cpu, target_rrp->rdata.hinfo.cpu) ||
- stricmp (search_rrp->rdata.hinfo.os, target_rrp->rdata.hinfo.os);
- break;
- case TYPE_MX:
- i = stricmp (search_rrp->rdata.mx.exch, target_rrp->rdata.mx.exch);
- break;
- case TYPE_SOA:
- i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
- break;
- default:
- i = -32755; /* unsupported */
- }
- return i;
- }
-
-
-
- static int
- compare_rr_list (register struct rr *rrlp, register struct rr *target_rrp)
- {
- while (rrlp != NULLRR) {
- if (compare_rr (rrlp, target_rrp) == 0)
- return 0;
- #ifdef DEBUG_PAIN
- if (Dtrace)
- tcmdprintf ("%15d %s\n", compare_rr (rrlp, target_rrp), target_rrp->name);
- #endif
- rrlp = rrlp->next;
- }
- return -32767;
- }
-
-
-
- /* Make a new copy of a resource record */
- static struct rr *
- copy_rr (register struct rr *rrp)
- {
- register struct rr *newrr;
-
- if (rrp == NULLRR)
- return NULLRR;
-
- newrr = (struct rr *) callocw (1, sizeof (struct rr));
-
- newrr->source = rrp->source;
- newrr->name = strdup (rrp->name);
- newrr->type = rrp->type;
- newrr->class = rrp->class;
- newrr->ttl = rrp->ttl;
- if (rrp->suffix != NULLCHAR)
- newrr->suffix = strdup (rrp->suffix);
- if ((newrr->rdlength = rrp->rdlength) == 0)
- return newrr;
-
- switch (rrp->type) {
- case TYPE_A:
- newrr->rdata.addr = rrp->rdata.addr;
- break;
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- newrr->rdata.name = strdup (rrp->rdata.name);
- break;
- case TYPE_HINFO:
- newrr->rdata.hinfo.cpu = strdup (rrp->rdata.hinfo.cpu);
- newrr->rdata.hinfo.os = strdup (rrp->rdata.hinfo.os);
- break;
- case TYPE_MX:
- newrr->rdata.mx.pref = rrp->rdata.mx.pref;
- newrr->rdata.mx.exch = strdup (rrp->rdata.mx.exch);
- break;
- case TYPE_SOA:
- newrr->rdata.soa.mname = strdup (rrp->rdata.soa.mname);
- newrr->rdata.soa.rname = strdup (rrp->rdata.soa.rname);
- newrr->rdata.soa.serial = rrp->rdata.soa.serial;
- newrr->rdata.soa.refresh = rrp->rdata.soa.refresh;
- newrr->rdata.soa.retry = rrp->rdata.soa.retry;
- newrr->rdata.soa.expire = rrp->rdata.soa.expire;
- newrr->rdata.soa.minimum = rrp->rdata.soa.minimum;
- break;
- default:
- break;
- }
- return newrr;
- }
-
-
-
- static struct rr *
- copy_rr_list (register struct rr *rrlp)
- {
- register struct rr **rrpp;
- struct rr *result_rrlp;
-
- rrpp = &result_rrlp;
- while (rrlp != NULLRR) {
- *rrpp = copy_rr (rrlp);
- rrpp = &(*rrpp)->next;
- rrlp = rrlp->next;
- }
- *rrpp = NULLRR;
- return result_rrlp;
- }
-
-
-
- /* Free (list of) resource records */
- void
- free_rr (register struct rr *rrlp)
- {
- register struct rr *rrp;
-
- while ((rrp = rrlp) != NULLRR) {
- rrlp = rrlp->next;
-
- free (rrp->comment);
- free (rrp->suffix);
- free (rrp->name);
- if (rrp->rdlength > 0) {
- switch (rrp->type) {
- case TYPE_A:
- break; /* Nothing allocated in rdata section */
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- free (rrp->rdata.name);
- break;
- case TYPE_HINFO:
- free (rrp->rdata.hinfo.cpu);
- free (rrp->rdata.hinfo.os);
- break;
- case TYPE_MX:
- free (rrp->rdata.mx.exch);
- break;
- case TYPE_SOA:
- free (rrp->rdata.soa.mname);
- free (rrp->rdata.soa.rname);
- break;
- default:
- break;
- }
- }
- free ((char *) rrp);
- }
- }
-
-
-
- static struct rr *
- make_rr (int source, char *dname, int16 dclass, int16 dtype, int32 ttl, int16 rdl, void *data)
- {
- register struct rr *newrr;
-
- newrr = (struct rr *) callocw (1, sizeof (struct rr));
-
- newrr->source = (char) source;
- newrr->name = strdup (dname);
- newrr->class = dclass;
- newrr->type = dtype;
- newrr->ttl = ttl;
- if ((newrr->rdlength = rdl) == 0)
- return newrr;
-
- switch (dtype) {
- case TYPE_A:
- {
- register uint32 *ap = (uint32 *) data;
-
- newrr->rdata.addr = *ap;
- }
- break;
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- newrr->rdata.name = strdup ((char *) data);
- break;
- case TYPE_HINFO:
- {
- register struct hinfo *hinfop = (struct hinfo *) data;
-
- newrr->rdata.hinfo.cpu = strdup (hinfop->cpu);
- newrr->rdata.hinfo.os = strdup (hinfop->os);
- }
- break;
- case TYPE_MX:
- {
- register struct mx *mxp = (struct mx *) data;
-
- newrr->rdata.mx.pref = mxp->pref;
- newrr->rdata.mx.exch = strdup (mxp->exch);
- }
- break;
- case TYPE_SOA:
- {
- register struct soa *soap = (struct soa *) data;
-
- newrr->rdata.soa.mname = strdup (soap->mname);
- newrr->rdata.soa.rname = strdup (soap->rname);
- newrr->rdata.soa.serial = soap->serial;
- newrr->rdata.soa.refresh = soap->refresh;
- newrr->rdata.soa.retry = soap->retry;
- newrr->rdata.soa.expire = soap->expire;
- newrr->rdata.soa.minimum = soap->minimum;
- }
- break;
- default:
- break;
- }
- return newrr;
- }
-
-
-
- /**
- ** Domain Cache Utilities
- **/
-
- static void
- dcache_add (register struct rr *rrlp)
- {
- register struct rr *last_rrp;
- struct rr *save_rrp;
-
- if (rrlp == NULLRR)
- return;
-
- save_rrp = rrlp;
- last_rrp = NULLRR;
- while (rrlp != NULLRR) {
- rrlp->last = last_rrp;
- last_rrp = rrlp;
- rrlp = rrlp->next;
- }
- if (last_rrp != NULLRR) {
- last_rrp->next = Dcache;
- if (Dcache != NULLRR)
- Dcache->last = last_rrp;
- Dcache = save_rrp;
- }
- }
-
-
-
- static void
- dcache_drop (register struct rr *rrp)
- {
- if (rrp->last != NULLRR)
- rrp->last->next = rrp->next;
- else
- Dcache = rrp->next;
- if (rrp->next != NULLRR)
- rrp->next->last = rrp->last;
- rrp->last =
- rrp->next = NULLRR;
- }
-
-
-
- /* Search cache for resource records, removing them from the cache.
- * Also, timeout cache entries, and trim cache to size.
- * (Calling with NULLRR is legal -- will timeout & trim only.)
- * Note that an answer from the cache cannot be authoritative, because
- * we cannot guarantee that all the entries remain from a previous request.
- * Returns RR list, or NULLRR if no record found.
- */
- static struct rr *
- dcache_search (struct rr *rrlp)
- {
- register struct rr *rrp, *test_rrp;
- struct rr **rrpp, *result_rrlp;
- int32 elapsed;
- time_t now;
- int count = 0;
-
- #ifdef DEBUG
- if (Dtrace && rrlp != NULLRR)
- tcmdprintf ("dcache_search: searching for %s\n", rrlp->name);
- #endif
-
- elapsed = (int32) (time (&now) - Dcache_time);
- Dcache_time = now;
-
- rrpp = &result_rrlp;
- for (rrp = Dcache; (test_rrp = rrp) != NULLRR;) {
- rrp = rrp->next;
- /* timeout entries */
- if (test_rrp->ttl > 0L
- && (test_rrp->ttl -= elapsed) <= 0L)
- test_rrp->ttl = 0L;
-
- if (compare_rr_list (rrlp, test_rrp) == 0) {
- dcache_drop (*rrpp = test_rrp);
- rrpp = &(*rrpp)->next;
- } else if (test_rrp->source == RR_FILE && ++count > Dcache_size) {
- dcache_drop (test_rrp);
- free_rr (test_rrp);
- }
- }
- *rrpp = NULLRR;
- return result_rrlp;
- }
-
-
-
- /* Move a list of resource records to the cache, removing duplicates. */
- static void
- dcache_update (register struct rr *rrlp)
- {
- if (rrlp == NULLRR)
- return;
-
- free_rr (dcache_search (rrlp)); /* remove duplicates, first */
- dcache_add (rrlp);
- }
-
-
-
- /**
- ** File Utilities
- **/
-
- static struct rr *
- get_rr (FILE *fp, struct rr *lastrrp)
- {
- char *line, *lp;
- struct rr *rrp;
- char *ttl, *class, *type, *data = NULLCHAR;
- char const *name;
- int i;
-
- corrupted:
- line = getline (fp);
- if (line == NULLCHAR) /* eof or error */
- return NULLRR;
-
- rrp = (struct rr *) callocw (1, sizeof (struct rr));
-
- rrp->source = RR_FILE;
-
- if (line[0] == '$') {
- data = strtok (line, delim);
- if (strnicmp (data, "$origin", 7) == 0) {
- data = strtok (NULLCHAR, delim);
- if (data != NULLCHAR)
- rrp->suffix = strdup (data);
- else { /* this is a corrupted domain.txt file */
- log (-1, "The domain.txt file seems corrupted! Check for '$origin' lines");
- goto corrupted;
- }
- line[strlen (line)] = ' ';
- rrp->comment = strdup (line);
- rrp->type = TYPE_MISSING;
- free (line);
- return rrp;
- }
- if (strnicmp (data, "$include", 8) == 0) {
- data = strtok (NULLCHAR, delim);
- if (data != NULLCHAR)
- rrp->suffix = strdup (data);
- else { /* this is a corrupted domain.txt file */
- log (-1, "The domain.txt file seems corrupted! Check for '$include' lines");
- goto corrupted;
- }
- line[strlen (line)] = ' ';
- rrp->comment = strdup (line);
- rrp->type = TYPE_INCLUDE;
- free (line);
- return rrp;
- }
- } else {
- if (lastrrp != NULLRR)
- if (lastrrp->suffix != NULLCHAR)
- rrp->suffix = strdup (lastrrp->suffix);
- }
-
- if (!isspace (line[0]) || lastrrp == NULLRR) {
- name = strtok (line, delim);
- lp = NULLCHAR;
- } else { /* Name field is missing */
- name = lastrrp->name;
- lp = line;
- }
-
- if (name != NULLCHAR && name[0] == '@') {
- if (rrp->suffix != NULLCHAR)
- name = rrp->suffix;
- else {
- if (Dsuffix != NULLCHAR)
- name = Dsuffix;
- else
- name = "ampr.org.";
- }
- }
- /* make the rrp->suffix the Dsuffix, if it is defined */
- if (Dsuffix != NULLCHAR && rrp->suffix == NULLCHAR)
- rrp->suffix = strdup (Dsuffix);
-
- if (name == NULLCHAR) {
- log (-1, "The domain.txt file seems corrupted! Check for lines with missing hostnames");
- goto corrupted;
- }
- i = (int) strlen (name);
- if (name[i - 1] != '.') {
- /* Tack on the current domain suffix if defined */
- if (rrp->suffix != NULLCHAR) {
- rrp->name = mallocw ((int16) i + strlen (rrp->suffix) + 2);
- sprintf (rrp->name, "%s.%s", name, rrp->suffix);
- } else {
- /* Tack on a trailing period if it's not there */
- rrp->name = mallocw ((unsigned) i + 2);
- strcpy (rrp->name, name);
- strcat (rrp->name, ".");
- }
- } else
- /* fully qualified domain name */
- rrp->name = strdup (name);
-
- ttl = strtok (lp, delim);
-
- if (ttl == NULLCHAR || (!isdigit (ttl[0]) && ttl[0] != '-')) {
- /* Optional ttl field is missing */
- rrp->ttl = (long) TTL_MISSING;
- class = ttl;
- } else {
- rrp->ttl = atol (ttl);
- class = strtok (NULLCHAR, delim);
- }
-
- if (class == NULLCHAR) {
- /* we're in trouble, but keep processing */
- rrp->class = CLASS_MISSING;
- type = class;
- } else if (class[0] == '<') {
- rrp->class = (int16) atoi (&class[1]);
- type = strtok (NULLCHAR, delim);
- } else if (stricmp (class, "IN") == 0) {
- rrp->class = CLASS_IN;
- type = strtok (NULLCHAR, delim);
- } else {
- /* Optional class field is missing; assume IN */
- rrp->class = CLASS_IN;
- type = class;
- }
-
- if (type == NULLCHAR) {
- /* we're in trouble, but keep processing */
- rrp->type = TYPE_MISSING;
- data = type;
- } else if (type[0] == '{') {
- rrp->type = (int16) atoi (&class[1]); /*lint !e613 */
- data = strtok (NULLCHAR, delim);
- } else {
- rrp->type = TYPE_MISSING;
- for (i = 1; i < NDTYPES; i++) {
- if (stricmp (type, Dtypes[i]) == 0) {
- rrp->type = (int16) i;
- data = strtok (NULLCHAR, delim);
- break;
- }
- }
- }
-
- if (rrp->type == TYPE_MISSING)
- data = NULLCHAR;
-
- if (data == NULLCHAR) {
- /* Empty record, just return */
- free (line);
- return rrp;
- }
- switch (rrp->type) {
- case TYPE_A:
- rrp->rdlength = 4;
- rrp->rdata.addr = aton (data);
- break;
- case TYPE_CNAME:
- i = (int) strlen (data);
- if (data[i - 1] != '.') { /* not fully qualified */
- if (rrp->suffix != NULLCHAR) {
- rrp->rdata.name = mallocw ((int16)i + strlen (rrp->suffix) + 2);
- sprintf (rrp->rdata.name, "%s.%s", data, rrp->suffix);
- } else {
- rrp->rdata.name = mallocw ((int16) i + 2);
- strcpy (rrp->rdata.name, data);
- strcat (rrp->rdata.name, ".");
- }
- } else
- rrp->rdata.name = strdup (data);
- rrp->rdlength = (int16) strlen (rrp->rdata.name);
- break;
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- rrp->rdlength = (int16) strlen (data);
- rrp->rdata.name = strdup (data);
- break;
- case TYPE_HINFO:
- rrp->rdlength = (int16) strlen (data);
- rrp->rdata.hinfo.cpu = strdup (data);
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR) {
- rrp->rdlength += (int16) strlen (data);
- rrp->rdata.hinfo.os = strdup (data);
- }
- break;
- case TYPE_MX:
- rrp->rdata.mx.pref = (int16) atoi (data);
- rrp->rdlength = 2;
-
- /* Get domain name of exchanger */
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR) {
- rrp->rdlength += (int16) strlen (data);
- rrp->rdata.mx.exch = strdup (data);
- }
- break;
- case TYPE_SOA:
- /* Get domain name of master name server */
- rrp->rdlength = (int16) strlen (data);
- rrp->rdata.soa.mname = strdup (data);
-
- /* Get domain name of irresponsible person */
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR) {
- rrp->rdata.soa.rname = strdup (data);
- rrp->rdlength += (int16) strlen (data);
- }
-
- {
- int corrupt = 0;
-
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
- rrp->rdata.soa.serial = atol (data);
- else
- corrupt = 1;
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
- rrp->rdata.soa.refresh = atol (data);
- else
- corrupt = 1;
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
- rrp->rdata.soa.retry = atol (data);
- else
- corrupt = 1;
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
- rrp->rdata.soa.expire = atol (data);
- else
- corrupt = 1;
- if ((data = strtok (NULLCHAR, delim)) != NULLCHAR)
- rrp->rdata.soa.minimum = atol (data);
- else
- corrupt = 1;
- if (corrupt) { /* this is a corrupted domain.txt file */
- log (-1, "The domain.txt file seems corrupted! Check for '$soa' lines");
- goto corrupted;
- }
- }
- rrp->rdlength += 20;
- break;
- default:
- break;
- }
-
- /* !!! need to handle trailing comments */
- free (line);
- return rrp;
- }
-
-
-
- /* Print a resource record */
- static void
- put_rr (FILE *fp, struct rr *rrp)
- {
- int trans;
- int trace = 0;
-
- if (fp == NULLFILE || rrp == NULLRR)
- return;
-
- if (fp == stdout)
- trace = 1;
-
- if (rrp->name == NULLCHAR && rrp->comment != NULLCHAR) {
- if (trace)
- tcmdprintf ("%s\n", rrp->comment);
- else
- fprintf (fp, "%s\n", rrp->comment);
- return;
- }
- if (trace)
- tcmdprintf ("%s", rrp->name);
- else
- fprintf (fp, "%s", rrp->name);
- if (rrp->ttl != (int32) TTL_MISSING) {
- if (trace)
- tcmdprintf ("\t%ld", rrp->ttl);
- else
- fprintf (fp, "\t%ld", rrp->ttl);
- }
- if (rrp->class == CLASS_IN) {
- if (trace)
- tcmdprintf ("\tIN");
- else
- fprintf (fp, "\tIN");
- } else {
- if (trace)
- tcmdprintf ("\t<%u>", rrp->class);
- else
- fprintf (fp, "\t<%u>", rrp->class);
- }
- if (rrp->type < NDTYPES) {
- if (trace)
- tcmdprintf ("\t%s", Dtypes[rrp->type]);
- else
- fprintf (fp, "\t%s", Dtypes[rrp->type]);
- } else {
- if (trace)
- tcmdprintf ("\t{%u}", rrp->type);
- else
- fprintf (fp, "\t{%u}", rrp->type);
- }
- if (rrp->rdlength == 0) {
- /* Null data portion, indicates nonexistent record */
- /* or unsupported type. Hopefully, these will filter */
- /* as time goes by. */
- if (trace)
- tcmdprintf ("\n");
- else
- fprintf (fp, "\n");
- return;
- }
- switch (rrp->type) {
- case TYPE_A:
- trans = DTranslate; /* Save IP address translation state */
- DTranslate = 0; /* Force output to be numeric IP addr */
- if (trace)
- tcmdprintf ("\t%s\n", inet_ntoa (rrp->rdata.addr));
- else
- fprintf (fp, "\t%s\n", inet_ntoa (rrp->rdata.addr));
- DTranslate = trans; /* Restore original state */
- break;
- case TYPE_CNAME:
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- case TYPE_NS:
- case TYPE_PTR:
- case TYPE_TXT:
- /* These are all printable text strings */
- if (trace)
- tcmdprintf ("\t%s\n", rrp->rdata.data);
- else
- fprintf (fp, "\t%s\n", rrp->rdata.data);
- break;
- case TYPE_HINFO:
- if (trace)
- tcmdprintf ("\t%s\t%s\n", rrp->rdata.hinfo.cpu, rrp->rdata.hinfo.os);
- else
- fprintf (fp, "\t%s\t%s\n", rrp->rdata.hinfo.cpu, rrp->rdata.hinfo.os);
- break;
- case TYPE_MX:
- if (trace)
- tcmdprintf ("\t%u\t%s\n", rrp->rdata.mx.pref, rrp->rdata.mx.exch);
- else
- fprintf (fp, "\t%u\t%s\n", rrp->rdata.mx.pref, rrp->rdata.mx.exch);
- break;
- case TYPE_SOA:
- if (trace)
- tcmdprintf ("\t%s\t%s\n\t%lu\t%lu\t%lu\t%lu\t%lu\n",
- rrp->rdata.soa.mname, rrp->rdata.soa.rname,
- rrp->rdata.soa.serial, rrp->rdata.soa.refresh,
- rrp->rdata.soa.retry, rrp->rdata.soa.expire,
- rrp->rdata.soa.minimum);
- else
- fprintf (fp, "\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
- rrp->rdata.soa.mname, rrp->rdata.soa.rname,
- rrp->rdata.soa.serial, rrp->rdata.soa.refresh,
- rrp->rdata.soa.retry, rrp->rdata.soa.expire,
- rrp->rdata.soa.minimum);
- break;
- default:
- if (trace)
- tcmdprintf ("\n");
- else
- fprintf (fp, "\n");
- break;
- }
- }
-
-
-
- static struct rr *
- dfile_search_file (struct rr *rrlp, const char *filename)
- {
- register struct rr *frrp;
- struct rr **rrpp, *result_rrlp, *oldrrp, *recurse_rrlp;
- int32 elapsed;
- FILE *dbase;
- struct stat dstat;
-
- if ((dbase = fopen (filename, READ_TEXT)) == NULLFILE)
- return NULLRR;
-
- if (fstat (fileno (dbase), &dstat) != 0) {
- tputs ("Dfile_Search: can't get file status\n");
- (void) fclose (dbase);
- return NULLRR;
- }
- if ((elapsed = (int32) (Dcache_time - (time_t) dstat.st_ctime)) < 0L)
- elapsed = -elapsed; /* arbitrary time mismatch */
-
- result_rrlp = NULLRR; /* for contiguous test below */
- oldrrp = NULLRR;
- rrpp = &result_rrlp;
- while ((frrp = get_rr (dbase, oldrrp)) != NULLRR) {
- if (frrp->type == TYPE_INCLUDE) {
- /* frrp->suffix contains the filename, and
- frrp->comment contains the entire line */
- recurse_rrlp = dfile_search_file (rrlp, frrp->suffix);
- free_rr (frrp);
- frrp = recurse_rrlp;
- if (frrp == NULLRR)
- continue;
- }
- free_rr (oldrrp);
- if (frrp->type != TYPE_MISSING && frrp->rdlength > 0 && compare_rr_list (rrlp, frrp) == 0) {
- if (frrp->ttl > 0L && (frrp->ttl -= elapsed) <= 0L)
- frrp->ttl = 0L;
- *rrpp = frrp;
- rrpp = &(*rrpp)->next;
- oldrrp = copy_rr (frrp);
- } else {
- oldrrp = frrp;
- /* All records of the same name and the same type
- are contiguous. Therefore, for a single query,
- we can stop searching. Multiple queries must
- read the whole file.
- */
- if (rrlp->next == NULLRR && result_rrlp != NULLRR)
- break;
- }
- if (!main_exit && Mprunning)
- kwait (NULL); /* run multiple sessions */
- }
- free_rr (oldrrp);
- *rrpp = NULLRR;
-
- (void) fclose (dbase);
- return result_rrlp;
- }
-
-
-
- /* Search local database for resource records.
- * Returns RR list, or NULLRR if no record found.
- */
- static struct rr *
- dfile_search (struct rr *rrlp)
- {
- struct rr *result_rrlp;
-
- #ifdef DEBUG
- if (Dtrace)
- tcmdprintf ("Dfile_Search: Searching for \"%s\"\n", rrlp->name);
- #endif
-
- while (Dfile_writing > 0)
- kwait (&Dfile_reading);
- Dfile_reading++;
-
- result_rrlp = dfile_search_file (rrlp, DomainFile);
-
- if (--Dfile_reading <= 0) {
- Dfile_reading = 0;
- ksignal (&Dfile_writing, 0);
- }
- return result_rrlp;
- }
-
-
-
- /* Process which will add new resource records from the cache
- * to the local file, eliminating duplicates while it goes.
- */
- static void
- dfile_update (int s OPTIONAL, void *unused OPTIONAL, void *p OPTIONAL)
- {
- struct rr **rrpp, *rrlp, *oldrrp;
- char *newname;
- FILE *old_fp, *new_fp;
- struct stat old_stat, new_stat;
-
- log (-1, "update DOMAIN.TXT initiated");
-
- close_s (Curproc->input);
- Curproc->input = -1;
- close_s (Curproc->output);
- Curproc->output = -1;
-
- newname = strdup (DomainFile);
- strcpy (&newname[strlen (newname) - 3], "tmp");
-
- while (Dfile_wait_absolute != 0L && !main_exit) {
- register struct rr *frrp;
- int32 elapsed;
-
- while (Dfile_wait_absolute != 0L) {
- elapsed = Dfile_wait_absolute - secclock ();
- Dfile_wait_absolute = 0L;
- if (elapsed > 0L && !main_exit) {
- kalarm (elapsed * 1000L);
- kwait (&Dfile_wait_absolute);
- kalarm (0L);
- }
- }
-
- log (-1, "update DOMAIN.TXT");
-
- /* create new file for copy */
- if ((new_fp = fopen (newname, WRITE_TEXT)) == NULLFILE) {
- printf ("Dfile_Update: can't create \"%s\"!\n", newname);
- break;
- }
- if (fstat (fileno (new_fp), &new_stat) != 0) {
- printf ("Dfile_Update: can't get new_file status!\n");
- (void) fclose (new_fp);
- break;
- }
- kwait (NULL); /* file operations can be slow */
-
- /* timeout the cache one last time before writing */
- (void) dcache_search (NULLRR);
-
- /* copy new RRs out to the new file */
- /* (can't wait here, the cache might change) */
- rrpp = &rrlp;
- for (frrp = Dcache; frrp != NULLRR; frrp = frrp->next) {
- switch (frrp->source) {
- case RR_QUESTION:
- case RR_ANSWER:
- case RR_AUTHORITY:
- case RR_ADDITIONAL:
- *rrpp = copy_rr (frrp);
- if (frrp->type != TYPE_MISSING
- && frrp->rdlength > 0)
- put_rr (new_fp, frrp);
- rrpp = &(*rrpp)->next;
- frrp->source = RR_FILE;
- break;
- default:
- break;
- }
- }
- *rrpp = NULLRR;
-
- /* open up the old file, concurrently with everyone else */
- if ((old_fp = fopen (DomainFile, READ_TEXT)) == NULLFILE) {
- /* great! no old file, so we're ready to go. */
- (void) fclose (new_fp);
- (void) rename (newname, DomainFile);
- free_rr (rrlp);
- break;
- }
- if (fstat (fileno (old_fp), &old_stat) != 0) {
- printf ("Dfile_Update: can't get old_file status!\n");
- (void) fclose (new_fp);
- (void) fclose (old_fp);
- free_rr (rrlp);
- break;
- }
- if ((elapsed = (int32) (new_stat.st_ctime - old_stat.st_ctime)) < 0L)
- elapsed = -elapsed; /* file times are inconsistant */
-
- /* Now append any non-duplicate records */
- oldrrp = NULLRR;
- while ((frrp = get_rr (old_fp, oldrrp)) != NULLRR) {
- free_rr (oldrrp);
- if (frrp->name == NULLCHAR
- && frrp->comment != NULLCHAR)
- put_rr (new_fp, frrp);
- if (frrp->type == TYPE_INCLUDE)
- frrp->type = TYPE_MISSING;
- if (frrp->type != TYPE_MISSING && frrp->rdlength > 0 && compare_rr_list (rrlp, frrp) != 0) {
- if (frrp->ttl > 0L && (frrp->ttl -= elapsed) <= 0L)
- frrp->ttl = 0L;
- if (frrp->ttl != 0 || !Dfile_clean)
- put_rr (new_fp, frrp);
- }
- oldrrp = frrp;
- if (!main_exit)
- kwait (NULL); /* run in background */
- }
- free_rr (oldrrp);
- (void) fclose (new_fp);
- (void) fclose (old_fp);
- free_rr (rrlp);
-
- /* wait for everyone else to finish reading */
- Dfile_writing++;
- while (Dfile_reading > 0)
- kwait (&Dfile_writing);
-
- unlink (DomainFile);
- (void) rename (newname, DomainFile);
-
- Dfile_writing = 0;
- ksignal (&Dfile_reading, 0);
- }
- free (newname);
-
- log (-1, "update DOMAIN.TXT finished");
- Dfile_updater = NULLPROC;
- }
-
-
-
- /**
- ** Domain Server Utilities
- **/
-
- static void
- dumpdomain (struct dhdr *dhp, int32 rtt)
- {
- struct rr *rrp;
-
- tcmdprintf ("response id %u (rtt %lu ms) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
- dhp->id, rtt, dhp->qr, dhp->opcode, dhp->aa, dhp->tc, dhp->rd,
- dhp->ra, dhp->rcode);
- tcmdprintf ("%u questions:\n", dhp->qdcount);
- for (rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
- tcmdprintf ("%s type %s class %u\n", rrp->name, Dtypes[rrp->type], rrp->class);
- tcmdprintf ("%u answers:\n", dhp->ancount);
- for (rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next)
- put_rr (stdout, rrp);
- tcmdprintf ("%u authority:\n", dhp->nscount);
- for (rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next)
- put_rr (stdout, rrp);
- tcmdprintf ("%u additional:\n", dhp->arcount);
- for (rrp = dhp->additional; rrp != NULLRR; rrp = rrp->next)
- put_rr (stdout, rrp);
- #ifndef UNIX
- (void) fflush (stdout);
- #endif
- }
-
-
-
- static int
- dns_makequery (op, srrp, buffer, buflen)
- int16 op; /* operation */
- struct rr *srrp; /* Search RR */
- char *buffer; /* Area for query */
- int16 buflen OPTIONAL; /* Length of same */
- {
- unsigned char *cp;
- char *cp1;
- char *dname, *sname;
- int16 parameter;
- int16 dlen, len;
-
- cp = (unsigned char *) buffer;
- /* Use millisecond clock for timestamping */
- cp = put16 (cp, (int16) msclock ());
- parameter = (int16) ((op << 11) | 0x0100); /* Recursion desired */
- cp = put16 (cp, parameter);
- cp = put16 (cp, 1);
- cp = put16 (cp, 0);
- cp = put16 (cp, 0);
- cp = put16 (cp, 0);
-
- sname = strdup (srrp->name);
- dname = sname;
- dlen = (int16) strlen (dname);
- for (;;) {
- /* Look for next dot */
- cp1 = strchr (dname, '.');
- if (cp1 != NULLCHAR)
- len = (int16) (cp1 - dname); /* More to come */
- else
- len = dlen; /* Last component */
- *cp++ = uchar(len); /* Write length of component */
- if (len == 0)
- break;
- /* Copy component up to (but not including) dot */
- strncpy ((char *) cp, dname, len);
- cp += len;
- if (cp1 == NULLCHAR) {
- *cp++ = 0; /* Last one; write null and finish */
- break;
- }
- dname += len + 1;
- dlen -= len + 1;
- }
- free (sname);
- cp = put16 (cp, srrp->type);
- cp = put16 (cp, srrp->class);
- return (char *)cp - buffer;
- }
-
-
-
- /* Domain server resolution loop
- * Returns: Any answers in cache
- * Future features - multiple queries and inverse queries */
- static void
- dns_query (struct rr *rrlp)
- {
- struct mbuf *bp;
- struct dhdr *dhp;
- struct dserver *dp; /* server list */
- int32 rtt, abserr;
- int tried = 0; /* server list has been retried (count) */
-
- if (((dp = Dservers) == NULLDOM) || !Mprunning) {
- if (!Mprunning)
- Mprunning_err = 1;
- return;
- }
-
- for (;;) {
- char *buf;
- int len;
- struct sockaddr_in server_in;
- int s;
- int rval;
-
- dp->queries++;
-
- s = socket (AF_INET, SOCK_DGRAM, 0);
- server_in.sin_family = AF_INET;
- server_in.sin_port = IPPORT_DOMAIN;
- server_in.sin_addr.s_addr = dp->address;
-
- if (Dtrace) {
- #if 0
- /* Make sure this only goes to the command screen
- * - K2MF */
- if (Current->output == Command->output)
- #endif
- tcmdprintf ("DNS_Query: Querying server (%s) for \"%s\"\n",
- inet_ntoa (dp->address), rrlp->name);
- }
- buf = mallocw (512);
- len = dns_makequery (0, rrlp, buf, 512);
- (void) sendto (s, buf, len, 0, (char *) &server_in, sizeof (server_in));
- free (buf);
- kalarm (max (dp->timeout, 100));
- /* Wait for something to happen */
- rval = recv_mbuf (s, &bp, 0, NULLCHAR, 0);
- kalarm (0L);
- close_s (s);
-
- if (Dtrace) {
- #if 0
- /* Make sure this only goes to the command screen
- * - K2MF */
- if (Current->output == Command->output)
- #endif
- tcmdprintf ("DNS_Query: Received message length %d, errno %d\n", rval, errno);
- }
- if (rval > 0)
- break;
-
- if (errno == EABORT)
- return; /* Killed by "reset" command */
-
- /* Timeout; back off this one and try another server */
- dp->timeouts++;
- dp->timeout <<= 1; /*lint !e703 */
-
- /* But we must have some sort of sensible limit - surely? */
- if (dp->timeout > (Dserver_maxwait * 1000L))
- dp->timeout = Dserver_maxwait * 1000L;
-
- if ((dp = dp->next) == NULLDOM) {
- dp = Dservers;
- if (Dserver_retries > 0 && ++tried > Dserver_retries)
- return;
- }
- }
-
- /* got a response */
- dp->responses++;
- dhp = (struct dhdr *) mallocw (sizeof (struct dhdr));
-
- (void) ntohdomain (dhp, &bp); /* Convert to local format */
-
- /* Compute and update the round trip time */
- rtt = (int32) ((int16) msclock () - dhp->id);
- abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
- dp->srtt = ((AGAIN - 1) * dp->srtt + rtt + (AGAIN / 2)) >> LAGAIN; /*lint !e704 */
- dp->mdev = ((DGAIN - 1) * dp->mdev + abserr + (DGAIN / 2)) >> LDGAIN; /*lint !e704 */
- dp->timeout = 4 * dp->mdev + dp->srtt;
-
- /* move to top of list for next time */
- if (dp->prev != NULLDOM) {
- dlist_drop (dp);
- dlist_add (dp);
- }
- if (Dtrace) {
- #if 0
- /* Make sure this only goes to the command screen - K2MF */
- if (Current->output == Command->output)
- #endif
- dumpdomain (dhp, rtt);
- }
- /* Add negative reply to answers. This assumes that there was
- * only one question, which is true for all questions we send.
- */
- if (dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)) {
- register struct rr *rrp;
- long ttl = 600L;/* Default TTL for negative records */
-
- /* look for SOA ttl */
- for (rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next) {
- if (rrp->type == TYPE_SOA)
- ttl = rrp->ttl;
- }
-
- /* make the questions the negative answers */
- for (rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
- rrp->ttl = ttl;
- } else {
- free_rr (dhp->questions);
- dhp->questions = NULLRR;
- }
-
- /* post in reverse order to maintain original order */
- dcache_update (dhp->additional);
- dcache_update (dhp->authority);
- dcache_update (dhp->answers);
- dcache_update (dhp->questions);
-
- Dfile_wait_absolute = secclock () + Dfile_wait_relative;
- if (Dfile_upd && Dfile_updater == NULLPROC) {
- Dfile_updater = newproc ("domain update",
- 1024, dfile_update, 0, NULL, NULL, 0);
- }
- #ifdef DEBUG
- if (Dtrace)
- keywait (NULLCHAR, 1); /* so we can look around */
- #endif
- free ((char *) dhp);
- return;
- }
-
-
-
- /**
- ** Resolver Utilities
- **/
-
- /* Return TRUE if string appears to be an IP address in dotted decimal;
- * return FALSE otherwise (i.e., if string is a domain name)
- */
- static int
- isaddr (register const char *s)
- {
- char c;
-
- if (s == NULLCHAR)
- return TRUE; /* Can't happen */
-
- while ((c = *s++) != '\0') {
- if (c != '[' && c != ']' && !isdigit (c) && c != '.')
- return FALSE;
- }
- return TRUE;
- }
-
-
-
- /* Search for resource records.
- * Returns RR list, or NULLRR if no record found.
- */
- static struct rr *
- resolver (register struct rr *rrlp)
- {
- register struct rr *result_rrlp;
- struct rr *lrrp, *nrrp, *xrrp;
-
- if ((result_rrlp = dcache_search (rrlp)) == NULLRR)
- result_rrlp = dfile_search (rrlp);
-
- if (result_rrlp == NULLRR || check_ttl (result_rrlp) != 0) {
- if (!DTransing || !DLTranslate) {
- dcache_add (result_rrlp); /* save any expired RRs */
- dns_query (rrlp);
- result_rrlp = dcache_search (rrlp);
- }
- }
- dcache_add (copy_rr_list (result_rrlp));
- /* N5KNX: dns_query() will store negative replies into the cache, so we must
- take care never to return them in the list of (valid) records. */
- xrrp = result_rrlp;
- lrrp = NULLRR;
- while(xrrp) {
- nrrp = xrrp->next;
- if (!(xrrp->rdlength)) { /* remove it from list */
- if (lrrp)
- lrrp->next = nrrp;
- else
- result_rrlp = nrrp;
- xrrp->next = NULLRR;
- free_rr(xrrp);
- } else
- lrrp = xrrp;
- xrrp = nrrp;
- }
-
- return result_rrlp;
- }
-
-
-
- /* general entry point for address -> domain name resolution.
- * Returns RR list, or NULLRR if no record found.
- */
- struct rr *
- inverse_a (uint32 ip_address)
- {
- struct rr *prrp;
- struct rr *result_rrlp;
- char pname[34];
-
- if (ip_address == 0L)
- return NULLRR;
-
- sprintf (pname, "%u.%u.%u.%u.IN-ADDR.ARPA.", lobyte (loword (ip_address)),
- hibyte (loword (ip_address)), lobyte (hiword (ip_address)),
- hibyte (hiword (ip_address)));
-
- prrp = make_rr (RR_QUERY, pname, CLASS_IN, TYPE_PTR, 0, 0, NULL);
-
- /* make list to speed search */
- prrp->next = make_rr (RR_INQUERY, NULLCHAR, CLASS_IN, TYPE_A, 0, 4, &ip_address);
-
- result_rrlp = resolver (prrp);
-
- free_rr (prrp);
- return result_rrlp;
- }
-
-
-
- /* general entry point for domain name -> resource resolution.
- * Returns RR list, or NULLRR if no record found.
- */
- /* Optional recursive search to resolve CNAME records that
- prevents proper handling of CNAME queries. Forces recursion to take
- place only at the resolver of the node originating the query.
- Modification introducted by Don Sandstrom, KG7CP, October 15, 1992.
- Additional mod by WG7J .
- Mod by N5KNX to return CNAME + associated A record when possible, if recurse==0.
- This makes it a better DNS server.
- */
-
- static struct rr *
- resolve_rr (const char *dname, int16 dtype, int recurse)
- {
- struct rr *prrp,*qrrp,*xrrp = NULLRR,*lrrp = NULLRR;
- struct rr *result_rrlp = NULLRR;
- char *sname;
- int looping;
-
- if (dname == NULLCHAR)
- return NULLRR;
-
- sname = domainsuffix (dname);
- qrrp = make_rr (RR_QUERY, sname, CLASS_IN, dtype, 0, 0, NULL);
- free (sname);
-
- looping = MAXCNAME;
- if (!recurse) {
- result_rrlp = resolver (qrrp);
- prrp = result_rrlp;
- while (prrp) {
- if (looping == MAXCNAME && prrp->type != dtype && dtype != TYPE_ANY) { /* CNAME || PTR */
- /* try once to expand to an A record */
- xrrp = resolve_rr (prrp->rdata.name, TYPE_A, 1);
- looping--;
- }
- lrrp = prrp;
- prrp = prrp->next;
- }
- if (looping != MAXCNAME) /* did we expand a CNAME/PTR record? */
- lrrp->next = xrrp; /*lint !e794 * add to end of result chain */
- #ifdef DEBUG
- if (Dtrace)
- put_rr (stdout, result_rrlp);
- #endif
- } else {
- while (looping > 0) {
- if ((result_rrlp = resolver (qrrp)) == NULLRR || result_rrlp->type == dtype)
- break;
- #ifdef DEBUG
- if (Dtrace)
- put_rr (stdout, result_rrlp);
- #endif
- /* Should be CNAME or PTR record */
- /* Replace name and try again */
- free (qrrp->name);
- qrrp->name = strdup (result_rrlp->rdata.name);
- free_rr (result_rrlp);
- result_rrlp = NULLRR;
- looping--;
- }
- }
- free_rr (qrrp);
- return result_rrlp;
- }
-
-
-
- /* main entry point for address -> domain name resolution.
- * Returns string, or NULLCHAR if no name found.
- */
- char *
- resolve_a (ip_address, shorten)
- uint32 ip_address; /* search address */
- int shorten; /* return only first part of name (flag)*/
- {
- struct rr *save_rrlp, *rrlp;
- char *result = NULLCHAR, *p;
-
- /* N7IPB - When we have a lot of unresolvable addresses such as subnet routes in
- * the routing table, domain translation can take a long time. The
- * following allows us to skip the translation process for any address
- * ending in .000 or .255. These are assumed to be either subnets or
- * broadcast addresses. Can be turned on and off with the 'domain subnet'
- * command.
- */
-
- DTransing = 1;
- if (((ip_address & 0x0ff) && ((ip_address & 0x0ff) ^ 0x0ff)) || Dsubnet_translate) {
- for (rrlp = save_rrlp = inverse_a (ip_address);
- rrlp != NULLRR && result == NULLCHAR;
- rrlp = rrlp->next) {
- if (rrlp->rdlength > 0) {
- switch (rrlp->type) {
- case TYPE_PTR:
- result = strdup (rrlp->rdata.name);
- break;
- case TYPE_A:
- result = strdup (rrlp->name);
- break;
- default:
- break;
- }
- }
- }
- free_rr (save_rrlp);
-
- /* From Dennis Goodwin, kb7dz.
- * when domain verbose is off,
- * this make a domain name line bbs.wg7j.ampr.org show as bbs.wg7j
- * as opposed to bbs, as the above code does.
- */
- if (result != NULLCHAR && shorten) {
- if (Dsuffix != NULLCHAR)
- /* domain name minus domain suffix */
- p = strstr (result, Dsuffix);
- else {
- /* domain name up to, and including the first period */
- p = strchr (result, '.');
- if (p != NULLCHAR)
- p++;
- }
- if (p != NULLCHAR)
- *p = '\0';
- }
- if (result != NULLCHAR && *result) {
- /* remove trailing . */
- for (p = result; *p; ++p)
- ;
- if (*(--p) == '.')
- *p = (char) 0;
- }
- /* end of mod */
- }
- DTransing = 0;
- return result;
- }
-
-
-
- /* Main entry point for domain name -> address resolution.
- * Returns 0 if name is currently unresolvable.
- */
- uint32
- resolve (const char *name)
- {
- register struct rr *rrlp;
- uint32 ip_address = 0;
-
- if (name == NULLCHAR || strlen(name) == 0)
- return 0;
-
- if (isaddr (name))
- return aton (name);
-
- if ((rrlp = resolve_rr (name, TYPE_A, 1)) != NULLRR && rrlp->rdlength > 0)
- ip_address = rrlp->rdata.addr;
-
- /* multi-homed hosts are handled here */
- if (rrlp != NULLRR && rrlp->next != NULLRR) {
- register struct rr *rrp;
- register struct route *rp;
- int16 cost = MAXINT16;
-
- rrp = rrlp;
- while (rrp != NULLRR) { /* choose the best of a set of routes */
- if (rrp->rdlength > 0 && (rp = rt_lookup (rrp->rdata.addr)) != NULLROUTE && rp->metric <= cost) {
- ip_address = rrp->rdata.addr;
- cost = (int16) rp->metric;
- }
- rrp = rrp->next;
- }
- }
- free_rr (rrlp);
- return ip_address;
- }
-
-
-
- /* Lookup alternative MX records. Upto 5 of them. -- Selcuk */
- int
- resolve_amx (char *name, uint32 not_this_one, uint32 Altmx[])
- {
- register struct rr *rrp, *arrp;
- char *sname;
- uint32 addr;
- int16 exists = 0, i, n, tmp[5];
-
- if (name == NULLCHAR)
- return exists;
-
- if (isaddr (name)) {
- if ((sname = resolve_a (aton (name), FALSE)) == NULLCHAR)
- return exists;
- } else
- sname = strdup (name);
-
- for (i = 0; i < 5; i++) { /* let's initialize */
- tmp[i] = MAXINT16;
- Altmx[i] = 0L;
- }
-
- i = 0;
- rrp = arrp = resolve_rr (sname, TYPE_MX, 1);
- /* Search this list of rr's for an MX record */
- while (rrp != NULLRR) {
- if (rrp->rdlength > 0 && (addr = resolve (rrp->rdata.mx.exch)) != 0L && addr != not_this_one) {
- for (n = i;; n--) {
- if (n > 0 && rrp->rdata.mx.pref < tmp[n - 1]) {
- tmp[n] = tmp[n - 1];
- Altmx[n] = Altmx[n - 1];
- } else {
- if (rrp->rdata.mx.pref < tmp[n]) {
- tmp[n] = rrp->rdata.mx.pref;
- Altmx[n] = addr;
- exists++;
- }
- break;
- }
- }
- if (i < 4)
- i++;
- }
- rrp = rrp->next;
- }
- free_rr (arrp);
-
- free (sname);
- return exists;
- }
-
-
-
- /* Main entry point for MX record lookup.
- * Returns 0 if name is currently unresolvable.
- *
- * TODO: If we have MX records of equal cost, we should randomize which
- * one we select.
- */
- uint32
- resolve_mx (const char *name)
- {
- register struct rr *rrp, *arrp;
- char *sname, *tmp, *cp;
- uint32 addr, ip_address = 0;
- int16 pref = MAXINT16;
- int16 localpref = MAXINT16;
-
- if (name == NULLCHAR)
- return 0;
-
- if (isaddr (name)) {
- if ((sname = resolve_a (aton (name), FALSE)) == NULLCHAR)
- return 0;
- } else
- sname = strdup (name);
-
- cp = sname;
- for ( ; ; ) {
- rrp = arrp = resolve_rr (sname, TYPE_MX, 1);
- /* Search this list of rr's for an MX record */
- while (rrp != NULLRR) {
- if (rrp->rdlength > 0) {
- addr = resolve (rrp->rdata.mx.exch);
- /*
- * If this is one of our interfaces,
- * report our master IP address to avoid
- * mail loops. Also record our preference.
- */
- if (ismyaddr (addr)) {
- addr = Ip_addr;
- if (rrp->rdata.mx.pref < localpref)
- localpref = rrp->rdata.mx.pref;
- }
- if (rrp->rdata.mx.pref < pref) {
- pref = rrp->rdata.mx.pref;
- ip_address = addr;
- }
- }
- rrp = rrp->next;
- }
- free_rr (arrp);
- if (ip_address != 0)
- break;
- /* Compose wild card one level up */
- if ((cp = strchr (cp, '.')) == NULLCHAR)
- break;
- tmp = mallocw (strlen (cp) + 2);
- sprintf (tmp, "*%s", cp); /* wildcard expansion */
- free (sname);
- sname = tmp;
- cp = sname + 2;
- }
- free (sname);
-
- /*
- * If the best MX record we found is not better than ourselves, then
- * there are no valid MX hosts we should consider.
- */
- if (pref > localpref)
- ip_address = 0;
-
- return ip_address;
- }
-
-
-
- /* Search for local records of the MB, MG and MR type. Returns list of
- * matching records.
- */
- struct rr *
- resolve_mailb (name)
- const char *name; /* local username, without trailing dot */
- {
- register struct rr *result_rrlp;
- struct rr *rrlp;
- char *sname;
-
- sname = strdup (name);
- rrlp = make_rr (RR_QUERY, sname, CLASS_IN, TYPE_MB, 0, 0, NULL);
- rrlp->next = make_rr (RR_QUERY, sname, CLASS_IN, TYPE_MG, 0, 0, NULL);
- rrlp->next->next = make_rr (RR_QUERY, sname, CLASS_IN, TYPE_MR, 0, 0, NULL);
- free (sname);
- if ((result_rrlp = dcache_search (rrlp)) == NULLRR)
- result_rrlp = dfile_search (rrlp);
-
- free_rr (rrlp);
- if (Dsuffix != NULLCHAR) {
- rrlp = result_rrlp;
- while (rrlp != NULLRR) { /* add domain suffix to data */
- if (rrlp->rdlength > 0 &&
- rrlp->rdata.name[rrlp->rdlength - 1] != '.') {
- sname = mallocw ((unsigned) (rrlp->rdlength +
- Dsuffixl + 2));
- sprintf (sname, "%s.%s", rrlp->rdata.name, Dsuffix);
- free (rrlp->rdata.name);
- rrlp->rdata.name = sname;
- rrlp->rdlength = (int16) strlen (sname);
- }
- rrlp = rrlp->next;
- }
- }
- dcache_add (copy_rr_list (result_rrlp));
- return result_rrlp;
- }
-
-
-
- /* Return "normalized" domain name, with default suffix and trailing '.'
- * Searches local cache for CNAME expansions.
- */
- char *
- domainsuffix (const char *dname)
- {
- char *sname, *tname, *pp;
- int l;
-
- if (dname == NULLCHAR)
- return NULLCHAR;
-
- if (isaddr (dname))
- /* convert to our canonic form */
- return strdup (inet_ntoa (aton (dname)));
-
- sname = strdup (dname);
- l = (int) strlen (sname);
- if ((pp = strrchr (sname, '.')) == NULLCHAR) {
- /* No dot in name. Try to add default suffix */
- if (Dsuffix != NULLCHAR) {
- /* Append default suffix */
- tname = mallocw ((unsigned) (l + Dsuffixl + 2));
- sprintf (tname, "%s.%s", sname, Dsuffix);
- free (sname);
- sname = tname;
- }
- } else {
- /* There is a dot in the name. Check last part of
- * name. If longer than 4 char it must be a name
- * 4 or less is probably a domain (org, army, uk)
- */
- if (Dsuffix != NULLCHAR) {
- if (strlen (pp) <= 5) {
- for (++pp; *pp; pp++) {
- if (isdigit (*pp))
- break;
- }
- if (*pp) {
- /* Append default suffix */
- tname = mallocw ((unsigned) (l + Dsuffixl + 2));
- sprintf (tname, "%s.%s", sname, Dsuffix);
- free (sname);
- sname = tname;
- }
- } else {
- /* name with dot (must be call + local domain) */
- tname = mallocw ((unsigned) (l + Dsuffixl + 2));
- sprintf (tname, "%s.%s", sname, Dsuffix);
- free (sname);
- sname = tname;
- }
- }
- }
-
- if (sname[strlen (sname) - 1] != '.') {
- /* Append trailing dot */
- tname = mallocw (strlen (sname) + 2);
- sprintf (tname, "%s.", sname);
- free (sname);
- sname = tname;
- }
- return sname;
- }
-
-
-
- #ifdef DSERVER
-
- /* Domain Name Server - based on the server in GRI-Nos 910828
- * ported to current NOS code by Johan. K. Reinalda, WG7J/PA3DIS
- *
- * - Does not answer more then one query per frame
- * - Gives non-authoritative answers to all queries.
- * - Does not reply with authority or additional RR's
- * - If no answers are found in local cache or domain.txt file,
- * remote servers, if configured, are queried.
- *
- *
- * v0.93 10/19/92 queries do not recurse anymore, but let the requester
- * do the recursion (Solves problem with CNAME queries)
- * v0.92 06/24/92 RR length bug fixed.
- * A,CNAME,MX,HINFO,PTR,NS,SOA queries now work
- * v0.91 06/22/92 MX has small bug with RR length indication
- * v0.90 06/20/92 Only supports a single type 'A' request per frame
- */
-
- static int Dsocket = -1;
-
- /* Process a query received by the DNS server */
- static void
- proc_query (int unused OPTIONAL, void *d, void *b)
- {
- struct dserver *dp;
- struct dhdr *dhdr;
- int i, len;
- char *buf;
- struct sockaddr_in server;
- struct rr *rrp, *rrans, *rrtmp;
- struct rr *qp;
-
- dp = (struct dserver *) d; /* The query address */
- dhdr = (struct dhdr *) b; /* The query in host format */
-
- rrans = NULLRR;
- qp = dhdr->questions;
-
- /* This does NOT loop and support multiple questions yet */
-
- dhdr->aa = 0;
- switch (qp->type) {
- case TYPE_A:
- case TYPE_MX:
- case TYPE_CNAME:
- case TYPE_HINFO:
- case TYPE_PTR:
- case TYPE_NS:
- case TYPE_SOA:
- /* Not all of the below types are implemented in resolve_rr() */
- /* Let the other side resolve CNAME references, do not recurse ! */
- if ((rrp = resolve_rr (qp->name, qp->type, 0)) != NULLRR && rrp->rdlength > 0) {
- /* we found an entry, go tell him */
- dhdr->rcode = NO_ERROR;
- dhdr->qr = RESPONSE;
- } else {
- /* we did not find an entry, go tell him */
- free_rr (rrp); /* in case rdlength==0 */
- rrp = (struct rr *) callocw (1, sizeof (struct rr));
-
- rrp->name = strdup (qp->name);
- rrp->type = qp->type;
- rrp->class = qp->class;
- rrp->ttl = 500L;
- rrp->rdata.addr = 0L;
- rrp->rdlength = 4; /* size of addr data */
- dhdr->rcode = NAME_ERROR;
- dhdr->qr = RESPONSE;
- }
- rrans = rrp;
- break;
- /* Search only the local cache and domain file for these next few */
- /* Is this a good idea ??? */
- case TYPE_MB:
- case TYPE_MG:
- case TYPE_MR:
- rrp = make_rr (RR_QUERY, qp->name, CLASS_IN, qp->type, 0, 0, NULL);
- if ((rrans = dcache_search (rrp)) == NULLRR)
- rrans = dfile_search (rrp);
-
- free_rr (rrp);
- break;
- default:
- dhdr->rcode = NOT_IMPL;
- dhdr->qr = RESPONSE;
- }
-
- /* Find the number of answer records */
- i = 0;
- rrtmp = rrans;
- while (rrtmp != NULLRR) {
- i++;
- /* KG7CP - - if no ttl in database, set the time-to-live value for
- * dns responses, unless no ttl value has been defined.
- */
- if (rrtmp->ttl == (int32) TTL_MISSING && Dns_ttl > 0L)
- rrtmp->ttl = Dns_ttl;
- rrtmp = rrtmp->next;
- }
- dhdr->ancount = (int16) i;
- dhdr->answers = rrans;
-
- /* Authority and Additional RR's not implemented yet. */
- dhdr->nscount = 0;
- dhdr->authority = NULLRR;
- dhdr->arcount = 0;
- dhdr->additional = NULLRR;
- dhdr->ra = 0; /* recursion NOT available */
-
- if (Dtrace) {
- tcmdprintf ("DNS: replying");
- dumpdomain (dhdr, 0);
- }
- /* Maximum reply size is 512, see rfc1034/1035 */
- /* buf = mallocw(512); */
- buf = mallocw (5120); /* quick patch */
- len = htondomain (dhdr, buf, 5120);
- if (len > 5120) /* insufficient buffer space, we've trashed the arena */
- where_outta_here (1, "proc_query");
-
- free_dhdr (dhdr);
-
- server.sin_family = AF_INET;
- server.sin_port = dp->port;
- server.sin_addr.s_addr = dp->address;
- (void) sendto (Dsocket, buf, len, 0, (char *) &server, sizeof (server));
- free (buf);
- free ((char *) dp);
- dns_process_count--;
- }
-
-
-
- /* Process to receive all domain server related messages */
- static void
- drx (int unused OPTIONAL, void *u OPTIONAL, void *p OPTIONAL)
- {
- struct sockaddr_in sock, from;
- int fromlen;
- struct mbuf *bp;
- struct dhdr *dhdr;
- struct dserver *dp;
- int foo;
-
- server_disconnect_io ();
- Dsocket = socket (AF_INET, SOCK_DGRAM, 0);
- sock.sin_family = AF_INET;
- sock.sin_addr.s_addr = INADDR_ANY;
- sock.sin_port = IPPORT_DOMAIN;
- if (bind (Dsocket, (char *) &sock, sizeof (sock)) == -1) {
- tputs ("DNS: can't bind\n");
- Dsocket = -1;
- return;
- }
- /* Now loop forever, processing queries */
- for (;;) {
- fromlen = sizeof (from);
- if ((foo = recv_mbuf (Dsocket, &bp, 0, (char *) &from, &fromlen)) == -1)
- break; /* Server closing */
- if (foo == 0)
- continue;
- dhdr = mallocw (sizeof (struct dhdr));
-
- (void) ntohdomain (dhdr, &bp);
- if (Dtrace) {
- tcmdprintf ("DNS: %u bytes from %s\n", foo, psocket ((struct sockaddr *) &from));
- dumpdomain (dhdr, 0);
- }
- if (dns_process_count >= dns_maxcli) { /* G8FSL */
- if (Dtrace)
- tcmdprintf ("DNS: ignored - too many processes\n");
- free_dhdr (dhdr);
- continue;
- }
- dns_process_count++;
- /* Process queries only */
- if (dhdr->qr == QUERY) {
- /* Queries from ourself will cause a loop ! */
- if (ismyaddr (from.sin_addr.s_addr) != NULLIF) {
- if (Dtrace)
- tcmdprintf ("DNS: question from myself ignored\n");
- free_dhdr (dhdr);
- dns_process_count--;
- continue;
- } else {
- dp = (struct dserver *) callocw (1, sizeof (struct dserver));
-
- dp->address = from.sin_addr.s_addr;
- dp->srtt = (Dserver_maxwait * 1000L) / MSPTICK;
- dp->timeout = dp->srtt * 2;
- dp->port = from.sin_port;
- if (dhdr->opcode == ZONEINIT) {
- /* ZONEINIT not implemented */
- free_dhdr (dhdr);
- free (dp);
- } else
- (void) newproc ("Domain server", 1024, proc_query, 0, (void *) dp, (void *) dhdr, 0);
- }
- }
- }
- }
-
-
-
- static int
- dodnsserver (int argc, char *argv[], void *p OPTIONAL)
- {
- if (argc == 1)
- tprintf ("Domain Nameserver: O%s\n", (Dsocket != -1) ? "n" : "ff");
- else {
- if (!stricmp (argv[1], "on")) {
- if (Dsocket == -1)
- /* Start domain server task */
- (void) newproc ("Domain listener", 1024, drx, 0, NULL, NULL, 0);
- } else {
- close_s (Dsocket);
- Dsocket = -1;
- }
- }
- return 0;
- }
-
-
-
- /* Free a domain message */
- static void
- free_dhdr (struct dhdr *dp)
- {
- if (dp->qdcount != 0)
- free_rr (dp->questions);
- if (dp->ancount != 0)
- free_rr (dp->answers);
- if (dp->nscount != 0)
- free_rr (dp->authority);
- if (dp->arcount != 0)
- free_rr (dp->additional);
- free ((char *) dp);
- }
-
-
-
- static int
- dodnsmaxcli (int argc, char *argv[], void *p OPTIONAL)
- {
- return setint (&dns_maxcli, "max. simultaneous DNS processes", argc, argv);
- }
-
-
-
- /* Resolves a name using local cache,
- local domain file or DNS if configured
- Updates local cache with result
- WA3DSP 12/93
- */
- static int
- dodomresolve (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
- {
- struct session *sp = (struct session *) 0;
- uint32 addr;
- int trans;
- int insession = 0;
-
- if (Curproc->input == Command->input) {
- if ((sp = newsession (argv[1], RESOLVE, 0)) == NULLSESSION) {
- tputs ("Cannot open session\n");
- return 1;
- } else
- insession = 1;
- }
- tprintf ("Resolving %s ...\n", argv[1]);
- if ((addr = resolve (argv[1])) == 0) {
- tprintf ("Host \"%s\" unresolvable\n", argv[1]);
- if (insession) {
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- }
- return 1;
- }
- trans = DTranslate;
-
- /* Force output to be hostname - K2MF */
- DTranslate = 1;
- tprintf ("%s =", inet_ntoa (addr));
-
- /* Force output to be numeric IP address */
- DTranslate = 0;
- tprintf (" %s\n", inet_ntoa (addr));
-
- /* Restore original state */
- DTranslate = trans;
- if (insession)
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- return 0;
- }
-
-
-
- /* Domain Query a specific DNS for a name
- Does NOT update local cache or domain file
- "domain query ucsd.edu wa3dsp.ampr.org [type] [maxtries] [timeout-ms]"
- WA3DSP 12/93
- */
- static int
- dodnsquery (int argc, char *argv[], void *p)
- {
- struct session *sp = (struct session *) 0;
- struct mbuf *bp;
- struct dhdr *dhp;
- struct rr *qrrp;
- struct rr *rrp;
- struct sockaddr_in server_in;
- uint32 address, ip_address;
- int32 rtt, timeout, y;
- int insession = 0, len, s, rval = 0, maxtries, x, count = 0;
- int i, Type = 0;
- char *sname, *buf;
- char tmpname[80], rec_type[20];
- char **margv;
- FILE *fp;
-
- if (!Mprunning) {
- Mprunning_err = 1;
- return 1;
- }
-
- if (Curproc->input == Command->input) {
- if ((sp = newsession (argv[1], DNSQUERY, 0)) == NULLSESSION) {
- tputs ("Cannot open session\n");
- return 1;
- } else
- insession = 1;
- }
- tprintf ("Resolving %s .....\n", argv[1]);
- if ((address = resolve (argv[1])) == 0L) {
- tprintf (Badhost, "Domain Nameserver", argv[1]);
- goto exit;
- }
- if (argc > 3) {
- strncpy (rec_type, argv[3], 20);
- (void) strupr (rec_type);
-
- for (i = 1; i < NDTYPES1; i += 2) {
- if (stricmp (rec_type, Dtypes1[i]) == 0) {
- Type = atoi (Dtypes1[i]);
- break;
- }
- }
-
- if (!Type) {
- tprintf ("Invalid type %s\n", rec_type);
- goto exit;
- }
- }
- if (isaddr (argv[2])) {
- ip_address = aton (argv[2]);
- sprintf (tmpname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
- lobyte (loword (ip_address)),
- hibyte (loword (ip_address)),
- lobyte (hiword (ip_address)),
- hibyte (hiword (ip_address)));
- if (!Type) {
- Type = TYPE_PTR;
- strcpy (rec_type, "PTR");
- }
- qrrp = make_rr (RR_QUERY, tmpname, CLASS_IN, (int16) Type, 0, 0, NULL);
- } else {
- sname = domainsuffix (argv[2]);
- if (!Type) {
- Type = TYPE_A;
- strcpy (rec_type, "A");
- }
- qrrp = make_rr (RR_QUERY, sname, CLASS_IN, (int16) Type, 0, 0, NULL);
- free (sname);
- }
-
- if (argc > 4) {
- int tmpi = atoi (argv[4]);
- x = (int) min (tmpi, 10);
- maxtries = (int) max (x, 1);
- } else
- maxtries = 3;
-
- if (argc > 5) {
- int32 tmpi = atol (argv[5]);
- y = (int32) min (tmpi, 200000L);
- timeout = (int32) max (y, 100L);
- } else
- timeout = 20000L;
-
- s = socket (AF_INET, SOCK_DGRAM, 0);
- server_in.sin_family = AF_INET;
- server_in.sin_port = IPPORT_DOMAIN;
- server_in.sin_addr.s_addr = address;
-
- tprintf ("Querying server (%s)\n for \"%s\" - timeout=%ldms Maxtries=%d\n\n",
- inet_ntoa (address), qrrp->name, timeout, maxtries);
-
- buf = mallocw (512);
- len = dns_makequery (0, qrrp, buf, 512);
- for (x = 0; x < maxtries; x++) {
- (void) sendto (s, buf, len, 0, (char *) &server_in, sizeof (server_in));
-
- kalarm (timeout);
-
- /* Wait for something to happen */
- rval = recv_mbuf (s, &bp, 0, NULLCHAR, 0);
- kalarm (0L);
-
- if (Dtrace)
- tcmdprintf ("DNS_Query: Received message length %d, errno %d\n", rval, errno);
- if (rval > 0 || errno == EABORT)
- break;
- }
- free (buf);
- close_s (s);
-
- if (rval > 0 && errno != EABORT) {
- dhp = (struct dhdr *) mallocw (sizeof (struct dhdr));
-
- (void) ntohdomain (dhp, &bp); /* convert to local format */
-
- rtt = (int32) ((int16) msclock () - dhp->id);
- tprintf ("Rtt to host %s = %ldms\n\n", argv[1], rtt);
- margv = (char **) callocw (2, sizeof (char *));
-
- (void) tmpnam (tmpname);
- fp = fopen (tmpname, WRITE_TEXT);
- if (fp != NULLFILE) {
- for (rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next) {
- count++;
- put_rr (fp, rrp);
- }
- (void) fclose (fp);
- }
- free_dhdr (dhp);
- if (count) {
- margv[1] = strdup (tmpname);
- (void) morecmd (2, margv, p);
- free (margv[1]);
- free (margv);
- } else
- tprintf ("No type (%s) records found at host %s for %s\n", rec_type, argv[1], qrrp->name);
-
- unlink (tmpname);
-
- } else
- tputs ("No response from Server\n");
-
- free_rr (qrrp);
-
- exit:
- if (insession) {
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- }
- return 0;
- }
- #endif /* DSERVER */
-
-
-
- #ifdef ALLCMD
- int
- dodomlook (int argc OPTIONAL, char *argv[], void *p)
- {
- char **margv;
-
- margv = (char **) callocw (3, sizeof (char *));
-
- margv[1] = strdup (DomainFile);
- margv[2] = strdup (argv[1]);
- (void) domore (3, margv, p);
- free (margv[1]);
- free (margv[2]);
- free (margv);
- return 0;
- }
-
- #endif
-